package com.xyzwps.orm.exposed.repository

import com.xyzwps.orm.exception.TagDuplicateException
import com.xyzwps.orm.model.Tag
import com.xyzwps.orm.repository.TagRepository
import com.xyzwps.orm.util.ExceptionUtils
import org.jetbrains.exposed.dao.IntEntity
import org.jetbrains.exposed.dao.IntEntityClass
import org.jetbrains.exposed.dao.id.EntityID
import org.jetbrains.exposed.dao.id.IntIdTable
import org.jetbrains.exposed.sql.Column
import org.jetbrains.exposed.sql.Database
import org.jetbrains.exposed.sql.transactions.transaction
import java.lang.IllegalStateException
import java.sql.SQLIntegrityConstraintViolationException
import java.util.*

/**
 * DAO 风格的 API
 */
class DaoTagRepository(private val db: Database) : TagRepository {

    override fun insert(tag: Tag): Int {
        try {
            return transaction(db) {
                TagEntity.new {
                    userId = tag.userId
                    tagName = tag.tagName
                }
            }.tagId.value
        } catch (ex: Exception) {
            if (ExceptionUtils.causedBy(ex, SQLIntegrityConstraintViolationException::class.java)) {
                throw TagDuplicateException(tag.tagName)
            } else {
                throw IllegalStateException(ex)
            }
        }
    }

    override fun update(tag: Tag) {
        try {
            transaction(db) {
                val entity = TagEntity.findById(tag.tagId) ?: return@transaction
                entity.tagName = tag.tagName
                entity.userId = tag.userId
            }
        } catch (ex: Exception) {
            if (ExceptionUtils.causedBy(ex, SQLIntegrityConstraintViolationException::class.java)) {
                throw TagDuplicateException(tag.tagName)
            } else {
                throw IllegalStateException(ex)
            }
        }
    }

    override fun delete(tagId: Int) {
        transaction(db) {
            val entity = TagEntity.findById(tagId) ?: return@transaction
            entity.delete()
        }
    }

    override fun selectByTagId(tagId: Int): Optional<Tag> {
        return transaction(db) {
            val entity = TagEntity.findById(tagId)
            Optional.ofNullable(entity?.toTag())
        }
    }

    override fun selectAllForUser(userId: Int): List<Tag> {
        return transaction(db) {
            val entities = TagEntity.find { TagTable.userId eq userId }
            entities.map { it.toTag() }
        }
    }
}

